package org.xmeta;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ActionListenerExecutor {
    private static final Logger log = Logger.getLogger(ActionListenerExecutor.class.getName());

    private final List<ActionListener> listenerList = new ArrayList<>();
    private int index = -1;

    protected void addListener(ActionListener actionListener) {
        listenerList.add(actionListener);
    }

    protected void addListener(List<ActionListener> actionListeners) {
        listenerList.addAll(actionListeners);
    }

    public int getCurrentIndex() {
        return index;
    }

    public int getListenerCount() {
        return listenerList.size();
    }

    public ActionListener getActionListener(int index) {
        return listenerList.get(index);
    }

    protected void doOnDoAction(Thing thing, String actionName, Action action, ActionContext actionContext, Map<String, Object> params) throws Exception {
        while (index < listenerList.size() - 1) {
            index++;
            ActionListener listener = listenerList.get(index);
            listener.onDoAction(thing, actionName, action, actionContext, params, this);
        }
    }

    protected void doOnDoActionFinished(Thing thing, String actionName, Action action, ActionContext actionContext,
                                        Map<String, Object> params, Object result) throws Exception {
        while (index >= 0) {
            ActionListener listener = listenerList.get(index);

            try {
                listener.onDoActionFinished(thing, actionName, action, actionContext, params, this, result);
            } catch (Throwable t) {
                log.log(Level.WARNING, "ActionListener onDoActionFinished exception, name=" + listener.getName(), t);
            }

            index--;
        }
    }

    protected void doOnInit(Action action, Object caller, ActionContext actionContext, Map<String, Object> params) throws Exception{
       while (index < listenerList.size() - 1) {
            index++;
            ActionListener listener = listenerList.get(index);
            listener.onInit(action, caller, actionContext, params, this);
        }
    }

    protected Throwable doOnSuccess(Action action, Object caller, ActionContext actionContext, Object result){
       while (index >= 0 ) {
            ActionListener listener = listenerList.get(index);

            try {
                listener.onSuccess(action, caller, actionContext, result, this);
            } catch (Throwable t) {
                log.log(Level.WARNING, "ActionListener onSuccess exception, name=" + listener.getName(), t);

                index--;
                return doOnException(action, caller, actionContext, t);
            }

            index--;
        }

        return null;
    }

    protected Throwable doOnException(Action action, Object caller, ActionContext actionContext, Throwable t) {
        Throwable throwable = t;
        while (index >= 0) {
            ActionListener listener = listenerList.get(index);

            try {
                listener.onException(action, caller, actionContext, throwable, this);
            } catch (Throwable tt) {
                log.log(Level.WARNING, "ActionListener doOnException exception, name=" + listener.getName(), t);

                throwable = tt;
            }

            index--;
        }

        return throwable;
    }
}
